const std = @import("std");
const Allocator = std.mem.Allocator;
const fmt = std.fmt;
const ArrayList = std.array_list.Managed;

pub const LogLevel = @import("../utils/logger.zig").LogLevel; // Reuse if needed
const logger = @import("../utils/logger.zig"); // For potential parsing errors

// Reusing and adapting the parser from logger.zig for OHLCV bars
pub const Bar = struct {
    timestamp_str: []const u8, // Keep original string for reference/logging
    // TODO: Add proper timestamp parsing later (e.g., to std.time.timestamp)
    open: f64,
    high: f64,
    low: f64,
    close: f64,
    volume: f64,

    // Parses a single CSV row string into a Bar.
    // Returns null if parsing fails (e.g., wrong number of fields, bad float format).
    pub fn parse(row_str: []const u8, allocator: Allocator) !?Bar {
        var parts = ArrayList([]const u8).init(allocator);
        defer parts.deinit();

        var tokenizer = std.mem.tokenizeAny(u8, row_str, ",");
        while (tokenizer.next()) |part| {
            // Simple trim whitespace
            const trimmed_part = std.mem.trim(u8, part, " \t\r\n");
            if (trimmed_part.len > 0) { // Avoid empty parts if commas are adjacent
                try parts.append(trimmed_part);
            }
        }

        if (parts.items.len != 6) {
            // Using logger directly might be too much coupling, consider returning error instead
            // logger.log(.Warn, "Could not parse OHLCV row (expected 6 fields, got {d}): {s}", .{ parts.items.len, row_str });
            std.debug.print("WARN: Could not parse OHLCV row (expected 6 fields, got {d}): {s}\n", .{ parts.items.len, row_str });
            return null; // Indicate parsing failure
        }

        var self: Bar = undefined;
        self.timestamp_str = parts.items[0]; // Keep as string for now

        // Use parseFloat permissive to handle potential whitespace or variations
        self.open = fmt.parseFloat(f64, parts.items[1]) catch |err| {
            std.debug.print("WARN: Could not parse Open price '{s}': {s}\n", .{ parts.items[1], @errorName(err) });
            return null;
        };
        self.high = fmt.parseFloat(f64, parts.items[2]) catch |err| {
            std.debug.print("WARN: Could not parse High price '{s}': {s}\n", .{ parts.items[2], @errorName(err) });
            return null;
        };
        self.low = fmt.parseFloat(f64, parts.items[3]) catch |err| {
            std.debug.print("WARN: Could not parse Low price '{s}': {s}\n", .{ parts.items[3], @errorName(err) });
            return null;
        };
        self.close = fmt.parseFloat(f64, parts.items[4]) catch |err| {
            std.debug.print("WARN: Could not parse Close price '{s}': {s}\n", .{ parts.items[4], @errorName(err) });
            return null;
        };
        self.volume = fmt.parseFloat(f64, parts.items[5]) catch |err| {
            std.debug.print("WARN: Could not parse Volume '{s}': {s}\n", .{ parts.items[5], @errorName(err) });
            return null;
        };

        return self;
    }
};

// --- Event Types ---

// Signal generated by the Strategy
pub const SignalType = enum { Long, Exit }; // BuyAndHold only needs Long/Neutral
pub const Signal = struct {
    type: SignalType,
    // timestamp: i64, // Timestamp of the data bar that generated the signal
    // asset: []const u8, // For multi-asset systems
};

// Order generated by the Portfolio based on a Signal
pub const OrderType = enum { MarketBuy, MarketSell }; // Simple types for now
pub const Order = struct {
    type: OrderType,
    quantity: f64, // How many units/shares
    // asset: []const u8,
    // id: u64, // Unique order ID
};

// Fill event generated by the Execution Handler
pub const Fill = struct {
    timestamp_str: []const u8, // Timestamp when the fill occurred (from the bar data)
    // timestamp_ns: i64, // Parsed timestamp
    order_type: OrderType, // Which order type was filled
    quantity: f64, // Quantity filled (might differ from order if partial fills allowed)
    fill_price: f64, // Price at which the order was filled
    commission: f64, // Cost of the transaction
    // asset: []const u8,
    // exchange_order_id: ?[]const u8,
};

// --- State Structures ---

// Represents a currently held position
pub const Position = struct {
    entry_price: f64,
    quantity: f64,
    // entry_timestamp_str: []const u8,
    // asset: []const u8,

    pub fn getMarketValue(self: Position, current_price: f64) f64 {
        return self.quantity * current_price;
    }

    pub fn getUnrealizedPnl(self: Position, current_price: f64) f64 {
        return (current_price - self.entry_price) * self.quantity;
    }
};
